/*Splay 平衡树
* 1.rotate(x) 将编号为x的点转到父节点的位置

* 2.splay(x,k) 将编号为x的点转到编号为k的点下面
    x会每次走两步，直到走到k下面
    为维护平衡树的效率
    每次splay时会把经过的路径反过来

* 3.用懒标记记录某点及其子树的翻转状态
    x的懒标记代表以x为根的子树对应的区间
    当翻转区间[l,r]时，将l-1转到根，r+1转到根的右儿子
                l-1
        [1~l-2]       r+1
                  [l~r] [r+2~n]
    改变r+1的左儿子的懒标记即可

* 4.启发式合并
    每次优先将小的集合合并到大的集合，时间复杂度可以达到 O(nlogn)
    
    建立 n 棵 splay 树，合并时用并查集维护信息，
    当要合并两棵 splay 树时，直接暴力将一棵 splay 树插入到另外一棵 splay 树上，
    可采用启发式合并：
        即将更小的 splay 树合并到更大的 splay 树上。

    当合并时，将节点一个一个插入 splay 树中时，
    完全可以利用该节点的状态编号而不必生成新的节点编号，
    另外 splay 树中的状态节点编号与中序遍历表示的值的编号是相等的，
    且所有操作没有改变其对应的关系，所以可以直接利用状态节点编号返回查询的信息
*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>

using namespace std;

const int N=1000010, INF=0x3f3f3f3f;

int n, m, root[N], fa[N], idx;
struct node{
    int s[2], pa;
    int v, size;
    int id; // 下标编号
    void init(int _v, int _id, int _pa)
    {
        v=_v, id=_id, pa=_pa; size = 1;
    }
}tree[N];

int find(int x) //找到 x 所在集合的根节点
{
    if(x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}

inline void pushup(int x)
{
    auto &L=tree[tree[x].s[0]], &R=tree[tree[x].s[1]];
    tree[x].size=L.size+R.size+1;
}

inline void rotate(int x)
{
    int y=tree[x].pa, z=tree[y].pa;
    int k=tree[y].s[1]==x;
    tree[z].s[tree[z].s[1]==y]=x, tree[x].pa=z;

    tree[y].s[k]=tree[x].s[k^1], tree[tree[x].s[k^1]].pa=y;
    tree[x].s[k^1]=y, tree[y].pa=x;
    pushup(y), pushup(x);
}

inline void Splay(int x, int k, int tr) //第tr棵树的splay 将节点x旋转到节点k下面，用于维护树的平衡
{
    while(tree[x].pa!=k)
    {
        int y=tree[x].pa, z=tree[y].pa;
        if(z!=k)
        {
            if((tree[y].s[1]==x) ^ (tree[z].s[1]==y)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if(!k) root[tr]=x;
}

inline void insert(int x, int id, int tr) //重要度x，编号id，在第tr棵树上插入
{
    int u=root[tr], fa=0;
    while(u) fa=u, u=tree[u].s[x>tree[u].v];
    u=++idx;
    if(fa) tree[fa].s[x>tree[fa].v]=u;
    tree[u].init(x, id, fa);
    Splay(u, 0, tr);
}

inline int get_k(int k, int tr)
{
    int u=root[tr];
    while(u)
    {
        auto &L=tree[tree[u].s[0]];
        if(L.size>=k) u=tree[u].s[0];
        else if(L.size+1==k) return tree[u].id;
        else k-=L.size+1, u=tree[u].s[1];
    }
    return -1;
}

inline void dfs(int u, int tr) //u拼接到tr上
{
    if(tree[u].s[0]) dfs(tree[u].s[0], tr);
    if(tree[u].s[1]) dfs(tree[u].s[1], tr);
    insert(tree[u].v, tree[u].id, tr); //在v上插入顶点

}

signed main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
    {
        fa[i]=root[i]=i;
        int v; scanf("%d", &v);
        tree[i].init(v, i, 0);
    }    
    idx=n;
    while(m--)
    {
        int a, b; scanf("%d%d", &a, &b);
        a=find(a), b=find(b);
        if(a!=b) //启发式合并
        {
            if(tree[root[a]].size > tree[root[b]].size) swap(a, b); //保证b>=a
            dfs(root[a], b);
            fa[a] = b; //a拼接到b上
        }
    }
    scanf("%d", &m);
    while(m--)
    {
        int a, b; char op[2]; 
        scanf("%s%d%d", op, &a, &b);
        if(*op == 'B')
        {
            a=find(a), b=find(b);
            if(a!=b) //启发式合并
            {
                if(tree[root[a]].size>tree[root[b]].size) swap(a, b);
                dfs(root[a], b);
                fa[a]=b;
            }
            
        }
        else
        {
            a=find(a);
            if(tree[root[a]].size<b) puts("-1");
            else printf("%d\n", get_k(b, a));
        }
    }
    return 0;
}